local constant                        = require "constant"
local util = require "util"
local math_random = math.random
local FIVE_COLOR_CATTLE_MIN_CARD_NUM  = 11
local table_insert                    = table.insert
local table_sort                      = table.sort
local math_floor                      = math.floor
local table_remove                    = table.remove
local M                               = {}
local CARD_TYPE_FUNC_MAP              = {}


local function make_card_id(sign, number)
    return sign * 100 + number
end

M.make_card_id = make_card_id

local function extract_card_number(card_id)
    local number = card_id % 100
    if number == 14 then
        number = 1 --拼三张A是14，牛牛为1
    end

    return number
end

M.extract_card_number = extract_card_number

local function get_card_color(card_id)
    return math_floor(card_id / 100)
end

M.get_card_color = get_card_color

local function sort_card_list(tile_list)
	table_sort(tile_list, function(a, b)  
    	if  extract_card_number(a) > extract_card_number(b) then 
    		return true
    	end 
        
    	if extract_card_number(a) == extract_card_number(b) then
    		--return a > b
    		--因为兼容老版本，方块为2，梅花1
    		if (math_floor(a / 100) == 1 and math_floor(b / 100) == 2) or 
    				(math_floor(a / 100) == 2 and math_floor(b / 100) == 1) then
    			return a < b
    		else 
    			return a > b
    		end
    		
    	end

    	return false
	end)
end

M.sort_card_list = sort_card_list



local function is_five_calves(tile_list)    --五小牛
    if extract_card_number(tile_list[1]) + extract_card_number(tile_list[2]) + 
        extract_card_number(tile_list[3]) + extract_card_number(tile_list[4]) +
        extract_card_number(tile_list[5]) <= 10 then
        return true
    end

    return false
end

local function is_four_bomb(tile_list)      --炸弹牛
    if extract_card_number(tile_list[1]) == extract_card_number(tile_list[2]) and 
        extract_card_number(tile_list[1]) == extract_card_number(tile_list[3]) and 
        extract_card_number(tile_list[1]) == extract_card_number(tile_list[4]) then
        return true
    elseif extract_card_number(tile_list[2]) == extract_card_number(tile_list[3]) and 
        extract_card_number(tile_list[2]) == extract_card_number(tile_list[4]) and 
        extract_card_number(tile_list[2]) == extract_card_number(tile_list[5]) then
        return true
    end

    return false
end

local function is_five_color_cattle(tile_list) --五花牛
    if extract_card_number(tile_list[1]) >= FIVE_COLOR_CATTLE_MIN_CARD_NUM and 
        extract_card_number(tile_list[2]) >= FIVE_COLOR_CATTLE_MIN_CARD_NUM and 
        extract_card_number(tile_list[3]) >= FIVE_COLOR_CATTLE_MIN_CARD_NUM and
        extract_card_number(tile_list[4]) >= FIVE_COLOR_CATTLE_MIN_CARD_NUM and 
        extract_card_number(tile_list[5]) >= FIVE_COLOR_CATTLE_MIN_CARD_NUM then
        return true
    end

    return false
end

local function is_gourd_cattle(tile_list)   --葫芦牛

	local function table_contains(t, element)
	  for _, value in pairs(t) do
	    if value == element then
	      return true
	    end
	  end
	  return false
	end



	local a1 = tile_list[1] % 100 
	local a2 = tile_list[2] % 100
	local a3 = tile_list[3] % 100
	local a4 = tile_list[4] % 100
	local a5 = tile_list[5] % 100
	
	local tmp = {}
	tmp[a1] = (tmp[a1] or 0) + 1	
	tmp[a2] = (tmp[a2] or 0) + 1
	tmp[a3] = (tmp[a3] or 0) + 1
	tmp[a4] = (tmp[a4] or 0) + 1
	tmp[a5] = (tmp[a5] or 0) + 1
	
	local k_tmp = {}
	for k, v in pairs(tmp) do
		if not table_contains(k_tmp, k) then
			--k_tmp.insert(k)
			table_insert(k_tmp, k)
		end
	end
	
	if (#k_tmp == 2) then
		if (k_tmp[1] == 2 or k_tmp[1] == 3) then
			return true
		end
	end


    return false
end

local function is_flush_cattle(tile_list)   --同花牛
	local a1 = math_floor(tile_list[1] / 100) 
	local a2 = math_floor(tile_list[2] / 100)
	local a3 = math_floor(tile_list[3] / 100)
	local a4 = math_floor(tile_list[4] / 100)
	local a5 = math_floor(tile_list[5] / 100)
	
	if (a1 == a2 and a1 == a3 and a1 == a4 and a1 == a5) then
		return true
	end

    return false
end

local function is_shunzi(tile_list)         --顺子牛
	sort_card_list(tile_list)
	local a1 = tile_list[1] % 100 
	local a3 = tile_list[3] % 100
	local a2 = tile_list[2] % 100
	local a4 = tile_list[4] % 100
	local a5 = tile_list[5] % 100
	if a5 + 1 == a4 and a4 + 1 == a3 and a3 + 1 == a2 and a2 + 1 == a1 then
		return true
	end 

    return false
end

local function is_straight_flush(tile_list) --同花顺
    return is_flush_cattle(tile_list) and is_shunzi(tile_list)
end

for _, card_type in pairs(constant.NN_NAME_SPECIAL_CARD_TYPE_MAP) do
    if card_type == constant.NN_NAME_SPECIAL_CARD_TYPE_MAP.STRAIGHT_FLUSH then
        CARD_TYPE_FUNC_MAP[card_type] = is_straight_flush
    elseif card_type == constant.NN_NAME_SPECIAL_CARD_TYPE_MAP.FIVE_CALVES then
        CARD_TYPE_FUNC_MAP[card_type] = is_five_calves
    elseif card_type == constant.NN_NAME_SPECIAL_CARD_TYPE_MAP.FOUR_BOMBS then
        CARD_TYPE_FUNC_MAP[card_type] = is_four_bomb
    elseif card_type == constant.NN_NAME_SPECIAL_CARD_TYPE_MAP.FIVE_COLOR_CATTLES then
        CARD_TYPE_FUNC_MAP[card_type] = is_five_color_cattle
    elseif card_type == constant.NN_NAME_SPECIAL_CARD_TYPE_MAP.GOURD_CATTLE then
        CARD_TYPE_FUNC_MAP[card_type] = is_gourd_cattle
    elseif card_type == constant.NN_NAME_SPECIAL_CARD_TYPE_MAP.FLUSH_CATTLE then
        CARD_TYPE_FUNC_MAP[card_type] = is_flush_cattle
    elseif card_type == constant.NN_NAME_SPECIAL_CARD_TYPE_MAP.SHUNZI then
        CARD_TYPE_FUNC_MAP[card_type] = is_shunzi
    end
end

local function calc_three_cards_number_sum(tile_list, i, j, k)
    local num_i = extract_card_number(tile_list[i])
    local num_j = extract_card_number(tile_list[j])
    local num_k = extract_card_number(tile_list[k])
    local num_sum = 0

    if num_i >= 10 then
        num_sum = num_sum + 0
    else
        num_sum = num_sum + num_i
    end

    if num_j >= 10 then
        num_sum = num_sum + 0
    else
        num_sum = num_sum + num_j
    end

    if num_k >= 10 then
        num_sum = num_sum + 0
    else
        num_sum = num_sum + num_k
    end

    return num_sum
end

local function get_left_two_cards(tile_list, i, j, k)
    local left_two = {}

    for n = 1, constant.NN_MAX_CARDS_COUNT, 1 do
        if n ~= i and n ~= j and n ~= k then
            table_insert(left_two, tile_list[n])
        end
    end

    return left_two
end

local function calc_two_cards_number_sum(left_two)
    local two_sum = 0
    local num_1 = extract_card_number(left_two[1])
    local num_2 = extract_card_number(left_two[2])

    if num_1 >= 10 then
        num_1 = 0
    end

    if num_2 >= 10 then
        num_2 = 0
    end

    two_sum = (num_1 + num_2) % 10

    if two_sum == 0 then
        two_sum = 10
    end

    return two_sum
end

local function get_cattle_number(tile_list)
    local count = #tile_list or constant.NN_MAX_CARDS_COUNT
    for i = 1, 3, 1 do
        for j = i + 1, count, 1 do 
            if i ~= j then
                for k = i + 2, count, 1 do
                    if k ~= j then
                        local three_num_sum = calc_three_cards_number_sum(tile_list, i, j, k)

                        if three_num_sum % 10 == 0 then
                            local left_two = get_left_two_cards(tile_list, i, j, k)
                            local cattle_number = calc_two_cards_number_sum(left_two)

                            return cattle_number
                        end
                    end
                end
            end
        end
    end

    return 0
end

local function get_card_type(tile_list, sorted_special_card_type_list)
     print(string.format("sorted_special_card_type_list(%s) CARD_TYPE_FUNC_MAP(%s)", 
         tostring_r(sorted_special_card_type_list), tostring_r(CARD_TYPE_FUNC_MAP)))
     print_r(tile_list)
	local tmp = {}
	for k, v in pairs(sorted_special_card_type_list) do
		tmp[k] = v
	end

	table.sort(tmp, function(a, b)
		return a > b
	end)

    --for _, card_type in pairs(sorted_special_card_type_list) do
    for _, card_type in ipairs(tmp) do

        local func = CARD_TYPE_FUNC_MAP[card_type]

        if func and func(tile_list) then
            return card_type
        end

    end

    return get_cattle_number(tile_list)
end

M.get_card_type = get_card_type

local function get_bomb_number(tile_list)
    if extract_card_number(tile_list[1]) == extract_card_number(tile_list[2]) then
        return extract_card_number(tile_list[1])
    else
        return extract_card_number(tile_list[2])
    end
end

M.get_bomb_number = get_bomb_number

local function compare_bomb_card(src_tile_list, dst_tile_list)
    local src_bomb_num = get_bomb_number(src_tile_list)
    local dst_bomb_num = get_bomb_number(dst_tile_list)

    if src_bomb_num > dst_bomb_num then
        return true
    else
        return false
    end
end

M.compare_bomb_card = compare_bomb_card

local function compare_card(src_type, src_tile_list, dst_type, dst_tile_list)
    if src_type > dst_type then
        return true
    end

    if src_type < dst_type then
        return false
    end

    if src_type == CT_FOUR_BOMBS then
        return compare_bomb_card(src_tile_list, dst_tile_list)
    else
    
        local a = src_tile_list[1]
        local b = dst_tile_list[1]

        if  extract_card_number(a) > extract_card_number(b) then 
            return true
        end 
    
        if extract_card_number(a) == extract_card_number(b) then
            --return a > b
            --因为兼容老版本，方块为2，梅花1 
			if (math_floor(a / 100) == 1 and math_floor(b / 100) == 2) or 
					(math_floor(a / 100) == 2 and math_floor(b / 100) == 1) then
    			return a < b
    		else 
    			return a > b
    		end
        end    
        
    	return false
    end
end
M.compare_card = compare_card

local function get_left_card(tile_list, i, j, k)

    for n = 1, 4, 1 do
        if n ~= i and n ~= j and n ~= k then
            return n
        end
    end

    return 1
end

--四张手牌是否有牛
function M.get_cattle_four_number(tile_list)
    if #tile_list ~= 4 then
        return 0
    end

    local count = #tile_list or constant.NN_MAX_CARDS_COUNT
    for i = 1, 3, 1 do
        for j = i + 1, count, 1 do 
            if i ~= j then
                for k = i + 2, count, 1 do
                    if k ~= j then
                        local three_num_sum = calc_three_cards_number_sum(tile_list, i, j, k)

                        if three_num_sum % 10 == 0 then
                            local index = get_left_card(tile_list, i, j, k)
                            extract_card_number(tile_list[index])
                            local cattle_number = extract_card_number(tile_list[index])
                            if cattle_number > 10 then
                                cattle_number = 10
                            end

                            return cattle_number
                        end
                    end
                end
            end
        end
    end

    return 0
end

local function copy_table(t)
    local new_t = {}

    for k,v in pairs(t) do
        new_t[k] = v
    end

    return new_t
end

local function remove_select_card_list(cards,rsp_card_list)
    for i = 1,#rsp_card_list do
        local card_id = rsp_card_list[i]
        for j=#cards,1,-1 do
            if cards[j] == card_id then
                table_remove(cards,j)
            end
        end
    end
end

function M.get_cards(cards,max_cards_power,min_cards_power,special_card_type_list)
    local card_type
    local count = 20
    local rsp_card_list = {}
    while count > 0 do
        local t = {}
        local new_cards = copy_table(cards)
        while #t < 5 do --随机取5个牌
            local index = math_random(1,#cards)
            table_insert(t, table_remove(new_cards,index))
        end
        -- local sort_t = copy_table(t)
        local sort_t = t
        sort_card_list(sort_t)

        local card_type = get_card_type(sort_t,special_card_type_list)
        if max_cards_power and min_cards_power then
            if compare_card(max_cards_power.card_type,max_cards_power.cards,card_type,sort_t) and
            compare_card(card_type,sort_t,min_cards_power.card_type,min_cards_power.cards) then
                rsp_card_list = t
                remove_select_card_list(cards, t)
                break
            end
        elseif max_cards_power and not min_cards_power then
            if compare_card(max_cards_power.card_type,max_cards_power.cards,card_type,sort_t) then
                rsp_card_list = t
                remove_select_card_list(cards, t)
                break
            end

        elseif not max_cards_power and min_cards_power then
            if compare_card(card_type,sort_t,min_cards_power.card_type,min_cards_power.cards) then
                rsp_card_list = t
                remove_select_card_list(cards, t)
                break
            end
        end

        count = count - 1
    end
    print("count =====================",count,  rsp_card_list)
    return rsp_card_list
end


local function make_card_number_set(card_id_list)
    local card_number_set = {}
    local get_card_number = function(card_id)
        local number = card_id % 100
        if number == 14 then
            number = 1 --拼三张A是14，牛牛为1
        end

        if number > 10 then
            number = 10
        end
        return number
    end

    for _,card_id in pairs(card_id_list) do

        local number = get_card_number(card_id)

        local t = card_number_set[number]
        if not t then t = {} card_number_set[number] = t end
        table_insert(t,card_id)
    end

    return card_number_set
end

M.make_card_number_set = make_card_number_set

return M
